package main

import (
	"fmt"
	"time"
)

func main() {
	defer Start("main")()
	A()
}

func A() {
	fmt.Println("A")
	defer Start("A")()
	B()
}

func B() {
	fmt.Println("B")
	defer Start("B")()
	C()
	D()
}
func C() {
	fmt.Println("C")
	time.Sleep(5 * time.Second)
	defer Start("C")()
}
func D() {
	fmt.Println("D")
	defer Start("D")()
	E()
}

func E() {
	fmt.Println("E")
	defer Start("E")()
}

type Trace struct {
	name     string
	start    time.Time
	parent   *Trace
	children []*Trace
}

var currentTrace *Trace

func Start(name string) func() {
	start := time.Now()
	parent := currentTrace
	t := &Trace{
		name:   name,
		start:  start,
		parent: parent,
	}
	currentTrace = t
	if parent != nil {
		parent.children = append(parent.children, t)
	}

	return func() {
		duration := time.Since(start)
		printTrace(t, duration, 0)
		currentTrace = parent
	}
}

func printTrace(t *Trace, duration time.Duration, level int) {
	indent := ""
	for i := 0; i < level; i++ {
		indent += "  "
	}
	fmt.Printf("%s%s: %v\n", indent, t.name, duration)

	for _, child := range t.children {
		printTrace(child, time.Since(child.start), level+1)
	}
}
